package util;

import java.util.Hashtable;

import predatorpreytest.fake.FakeSheep;
import predatorpreytest.fake.FakeWolf;

import ratkit.repast.RepastTestEnvironment;
import repast.simphony.context.Context;
import PredatorPrey.Grass;
import PredatorPrey.Sheep;
import PredatorPrey.SimpleAgent;
import PredatorPrey.Wolf;

/**
 * This class provides the creation of elements of the PredatorPrey simulation
 * models in an essential manner.
 * 
 * @author İbrahim Çakırlar
 * @version 1.0
 */
public class PredatorPreyEnvironment extends RepastTestEnvironment {

	/**
	 * Environment instance..
	 */
	private static PredatorPreyEnvironment instance = null;

	/**
	 * List of existing agents in the environment.
	 */
	private Hashtable<String, Object> agents;

	/**
	 * List of died agents from the environment.
	 */
	private Hashtable<String, Object> diedAgents;

	/**
	 * Creates a new environment for the simulation model...
	 */
	private PredatorPreyEnvironment() {
		super("PredatorPrey Agent Factory");
		// initialize agent lists..
		this.setAgents(new Hashtable<String, Object>());
		this.setDiedAgents(new Hashtable<String, Object>());
	}

	/**
	 * Returns the singleton instance of the simulation environment.
	 * 
	 * @return instance of the environment.
	 */
	public static PredatorPreyEnvironment getInstance() {
		if (instance == null) {
			instance = new PredatorPreyEnvironment();
		}
		return instance;
	}

	/**
	 * Creates a new live Grass agent with the given context, x-y coordinate and
	 * name. If the Grass agent is not alive agent instance does not effects
	 * test scenario execution.
	 * 
	 * @param agentName
	 *            name of the agent.
	 * @param context
	 *            context of the agent to test.
	 * @param x
	 *            x coordinate of the agent.
	 * @param y
	 *            y coordinate of the agent.
	 * @return a new grass agent instance with given parameters.
	 */
	@SuppressWarnings("rawtypes")
	public Grass createGrass(String agentName, Context context, int x, int y) {
		Grass grass = new Grass(context, x, y);
		getAgents().put(agentName, grass);
		return grass;
	}

	/**
	 * Resets the environment memory.
	 */
	public void reset() {
		this.setAgents(new Hashtable<String, Object>());
		this.setDiedAgents(new Hashtable<String, Object>());
	}

	/**
	 * @param agents
	 *            list of agents to set to the test environment.
	 */
	public void setAgents(Hashtable<String, Object> agents) {
		this.agents = agents;
	}

	/**
	 * @return a list of live agent in the environment.
	 */
	public Hashtable<String, Object> getAgents() {
		return agents;
	}

	/**
	 * @param diedAgents
	 *            list of dies agents to set.
	 */
	public void setDiedAgents(Hashtable<String, Object> diedAgents) {
		this.diedAgents = diedAgents;
	}

	/**
	 * @return a list of dies agents in the test environment.
	 */
	public Hashtable<String, Object> getDiedAgents() {
		return diedAgents;
	}

	/**
	 * Returns the created agent instance with given agent name...
	 * 
	 * @param key
	 *            name of the created agent.
	 * @return live agent instance.
	 */
	public Object getAgent(String key) {
		return getAgents().get(key);
	}

	/**
	 * Creates a new sheep instance for test.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @return created sheep instance.
	 */
	public Sheep createSheep(String agentName) {
		Sheep wolf = new Sheep();
		getAgents().put(agentName, wolf);
		return wolf;
	}

	/**
	 * Creates a new fake sheep instance for test.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @return created wolf instance.
	 */
	public Sheep createFakeSheep(String agentName) {
		FakeSheep fSheep = new FakeSheep();
		getAgents().put(agentName, fSheep);
		return fSheep;
	}

	/**
	 * Creates a new simple agent instance for test.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @return created test agent instance.
	 */
	public SimpleAgent createSimpleAgent(String agentName) {
		SimpleAgent simpleAgent = new SimpleAgent();
		simpleAgent.setEnergy(Math.random() * 100);
		simpleAgent.setHeading(Math.random() * 360);
		getAgents().put(agentName, simpleAgent);
		return simpleAgent;
	}

	/**
	 * Creates a new wolf instance for test with given name.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @return created wolf instance.
	 */
	public Wolf createWolf(String agentName) {
		Wolf wolf = new Wolf();
		getAgents().put(agentName, wolf);
		return wolf;
	}

	/**
	 * Creates a new fake wolf instance for test with given name.
	 * 
	 * @param agentName
	 *            name of the agent
	 * @return created wolf instance.
	 */
	public FakeWolf createFakeWolf(String agentName) {
		FakeWolf wolf = new FakeWolf();
		getAgents().put(agentName, wolf);
		return wolf;
	}
}
